#!/usr/bin/env python
'''
Class Proxy_Tester
~By Norph@Intern0t

Tests proxies in a varies of ways
Threading should be done by the script controlling the Proxy_Tester (ie. make a proxy tester with a mere 10 proxies or so)
'''
import socket, urllib, urllib2, re

class Proxy_Tester(object):
    def __init__(self, ip=None, port=None):
        self.ip = []
        self.port = []
        
        if ip is not None and port is not None:
            if len(ip)>1 and len(port)>1:
                if len(ip)==len(port):
                    self.ip = ip[:]
                    self.port = port[:]
            else:
                self.ip.append(ip)
                self.port.append(port)
            
    
    def add_server(self, ip, port):
        if ip is None or port is None:
            return False
            
        self.ip.append(ip)
        self.port.append(port)
        return True
    
    def add_server_list(self, ip_list, port_list):
        if len(ip_list) != len(port_list):
            return False
        self.ip.extend(ip_list)
        self.port.extend(port_list)
        
        return True
    
    def clear_list(self):
        self.ip = []
        self.port = []
    
    def online_test_freeproxy(self, timeout=10, proxy_types_tested="all"):
        '''
        online_test
            uses checker.freeproxy.ru/checker/
            It's slow, but reliable
            
        proxy_types_tested can be:
                "all"        - Test all types of proxies (default)
                "allhttp"    - Test all http type proxies
                "allsocks"    - Test all socks type proxies
                "socks4"    - Test sock4
                "socks5"    - Test socks5...
                "http"        - Test http..
                "connect"    - Test connect (https) proxies
        
        RETURNS a dictionary with proxy type and the ip's in it
        '''
        if not self.ip or not self.port:
            return False
        
        #The following part could be optimized..
        proxies = []
        for i in range(0,len(self.ip)):
            proxies.append("%s:%d" % (self.ip[i], int(self.port[i])))
        
        #Set correct headers etc.
        url = "http://www.checker.freeproxy.ru/checker/index.php"
        headers = { "User-Agent" : "Mozilla/5.0 (compatible; Konqueror/3.5.8; Linux)",
                    "Referer" : "http://www.checker.freeproxy.ru/checker/",
                "Cookie" : "hotlog=1"}
        
        proxy_text = "\r\n".join(proxies)
        
        #Get the url (it's POST)
        data = urllib.urlencode(dict(proxy=proxy_text, timeout=str(timeout), ProxyType="all"))
        the_page = urllib2.urlopen(urllib2.Request(url, data, headers)).read()
        
        working = {}
        
        #Split in types (ie. HTTP/HTTPS/etc.)
        r = re.compile("(?:Good (.*?) proxies(.*?)(?:<center>|<a ))", re.DOTALL)
        m = re.findall(r, the_page)
        for p_list in m:
            type, content = p_list
            
            #Get the ip's as a list
            r = re.compile("((?:\d{1,3}\.){3}\d{1,3}:\d{0,5})", re.DOTALL)
            ips = re.findall(r, content)
            
            #Fill in the dictionary like: {"https":["ip:port","ip:port",...]}
            working[type.lower()] = ips
        
        return working
    
    def online_test_ipaddress(self):
        '''
            Better than freeproxy, but doesn't tell about the type of proxy
        '''
        if not self.ip or not self.port:
            return false
        
        
        #Set correct headers etc.
        url = "http://www.ip-adress.com/Proxy_Checker/"
        headers = { "User-Agent" : "Mozilla/5.0 (compatible; Konqueror/3.5.8; Linux)",
        "Referer" : "http://www.ip-adress.com/Proxy_Checker/"}
        
        working = []
        for i in range(0,len(self.ip)):
            data = urllib.urlencode(dict(proxy="%s:%d" % (self.ip[i],self.port[i])))
            the_page = urllib2.urlopen(urllib2.Request(url, data, headers)).read()
            
            if the_page.find('>working</span>.<br>')>-1:
                working.append("%s:%d" % (self.ip[i], self.port[i]))
        
        return working
    
    def tcp_conn_test(self, timeout=10):
        '''
        tcp_conn_test
            Designed to be faster, but not as reliable (in fact, might be a bad idea to use..)
            Just opens a socket and reports if it's succesful or not 
                (ie. do the server allow TCP connections to the specified port)
            
            I've noticed that ALOT of server pass this test... not sure how reliable this test is
            
            RETURNS a list of the servers that allowed a TCP connection on that port
        '''
        if not self.ip or not self.port:
            return False
        
        working = []
        for i in range(0,len(self.ip)):
            try:
                the_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            except:
                print "Could not create socket"
                continue
            
            try:
                the_sock.settimeout(timeout)
                the_sock.connect((self.ip[i], self.port[i]))
            except:
                the_sock.close()
                continue
            
            working.append("%s:%d" % (self.ip[i], self.port[i]))
            the_sock.close()
        
        return working
    
    def try_connect(self, to=10):
        '''
        try_connect
            Tries to connect to google using the proxies.
            Might be slow, but it's reliable
            
            RETURNS a dictionary with proxy type and the ip's in it (as online test)
        '''
        working = {}
        httpworking = []
        httpsworking=[]
        socks4working=[]
        socks4aworking=[]
        socks5working=[]
        for i in range(0,len(self.ip)):
            #try http
            try:
                urllib.urlopen    ("http://www.google.com", proxies={"http":"%s:%d" % (self.ip[i], self.port[i])})
            except IOError:
                continue
            httpworking.append("%s:%d" % (self.ip[i], self.port[i]))
            
        for i in range(0,len(self.ip)):
            #try https
            try:
                urllib.urlopen    ("http://www.google.com", proxies={"https":"%s:%d" % (self.ip[i], self.port[i])})
            except IOError:
                continue
            httpsworking.append("%s:%d" % (self.ip[i], self.port[i]))
            
        
        #Socks testing doesn't work atm...
        return False
        
        try:
            #pycurl
            import pycurl
            
            for i in range(0,len(self.ip)):
                #socks4
                c = pycurl.Curl()
                c.setopt(pycurl.URL, "http://www.google.com")
                c.setopt(pycurl.PROXY, self.ip[i])
                c.setopt(pycurl.PROXYPORT, self.port[i])
                c.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS4)
                
                while 1:
                    try:
                        c.perform()
                    except:
                        break
                    socks4working.append("%s:%d" % (self.ip[i], self.port[i]))
                    break
                
                #socks4a
                c.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS4A)
                
                while 1:
                    try:
                        c.perform()
                    except:
                        break
                    socks4working.append("%s:%d" % (self.ip[i], self.port[i]))
                    break
                
                #socks5
                c.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5)
                
                while 1:
                    try:
                        c.perform()
                    except:
                        break
                    socks4working.append("%s:%d" % (self.ip[i], self.port[i]))
                    break
            #/pycurl
            
        except ImportError:
            try:
                #socksipy
                import socks, httplib2
                
                print "trying socksipy with httplib2"
                httplib2.debuglevel=4
                
                for i in range(0,len(self.ip)):
                    #socks4
                    h = httplib2.Http(proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_SOCKS4, self.ip[i], self.port[i]), timeout=to)
                    
                    while 1:
                        try:
                            print "connecting with socks4"
                            r,c = h.request("http://www.google.com")
                        except:
                            break
                        socks4working.append("%s:%d" % (self.ip[i], self.port[i]))
                        break
                
                    #socks4a
                    h = httplib2.Http(proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_SOCKS4, self.ip[i], self.port[i], True), timeout=to)
                    
                    while 1:
                        try:
                            print "connecting with socks4a"
                            r,c = h.request("http://www.google.com")
                        except:
                            break
                        socks4aworking.append("%s:%d" % (self.ip[i], self.port[i]))
                        break
                
                    #socks5
                    h = httplib2.Http(proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_SOCKS5, self.ip[i], self.port[i], True), timeout=to)
                    
                    while 1:
                        try:
                            print "connecting with socks5"
                            r,c = h.request("http://www.google.com")
                        except:
                            break
                        socks5working.append("%s:%d" % (self.ip[i], self.port[i]))
                        break
                
                #/socksipy
            except ImportError:
                print "Cannot test socks proxies without online test.."
        
        working["http"] = httpworking[:]
        working["https"]=httpsworking[:]
        working["socks4"]=socks4working[:]
        working["socks4a"]=socks4aworking[:]
        working["socks5"]=socks5working[:]
        
        return working
    


if __name__ == "__main__":
    #For testing.
    p = Proxy_Tester()
    while 1:
        lol = raw_input("ip:port - ")
        if lol is "":
            break
        ip, port = lol.split(":")
        p.add_server(ip, int(port))
    
    #p.online_test(10)
    #p.tcp_conn_test(5)
    print p.try_connect()